package info.xmlprint.ui.widgets;

import info.xmlprint.core.mapping.ElementPath;
import info.xmlprint.core.mapping.ElementPathNode;
import info.xmlprint.core.project.PrintProject;
import info.xmlprint.core.xml.PElement;
import info.xmlprint.core.xml.XMLScanner;
import info.xmlprint.run.Constants;
import info.xmlprint.ui.message.GuiMessages;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.dom4j.Element;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;
import org.jaxen.JaxenException;
import org.jaxen.SimpleNamespaceContext;
import org.jaxen.dom4j.Dom4jXPath;

public class ElementPostionTreeViewer extends TreeViewer implements
		ISubjectControl, IObserverControl, ISetupComposite {

	private Image rightImg = new Image(null, this.getClass()
			.getResourceAsStream(Constants.RIGHT_IMG));
	private Shell shell;
	private XMLScanner xmlScanner;

	public ElementPostionTreeViewer(Composite parent, int style) {
		super(parent, style);
		init();
	}

	@SuppressWarnings("unchecked")
	private List<Element> getDocNodes(String xPathStr, Object doc,
			SimpleNamespaceContext nsMap) {
		Dom4jXPath xPath = null;
		try {
			xPath = new Dom4jXPath(xPathStr);
		} catch (JaxenException e1) {
			e1.printStackTrace();
			MessageDialog.openError(null, GuiMessages.Stileditor_Error_Error,
					GuiMessages.Stileditor_Error_XPathError);
		}

		xPath.setNamespaceContext(nsMap);

		List<Element> list = null;
		try {
			list = xPath.selectNodes(doc);
		} catch (JaxenException e1) {
			e1.printStackTrace();
			MessageDialog.openError(null, GuiMessages.Stileditor_Error_Error,
					GuiMessages.Stileditor_Error_XPathError);

		}
		return list;
	}

	private void init() {
		final Tree tree = getTree();
		shell = tree.getShell();
		tree.setLinesVisible(true);
		tree.setHeaderVisible(true);
		TreeColumn treeColumn = new TreeColumn(tree, SWT.LEFT);
		treeColumn.setWidth(200);
		treeColumn.setText(GuiMessages.Stileditor_Gui_Position + ":");

		// setContentProvider
		setContentProvider(new ITreeContentProvider() {
			public void dispose() {
			}

			public Object[] getChildren(Object parentElement) {
				if (parentElement instanceof ElementPathNode) {
					ElementPathNode pn = (ElementPathNode) parentElement;
					return pn.getChildrens();
				}
				return null;
			}

			public Object[] getElements(Object in) {
				if (in instanceof ElementPath) {
					ArrayList<ElementPathNode> list = new ArrayList<ElementPathNode>();
					ElementPath ef = (ElementPath) in;
					list.add(ef.getRoot());
					return list.toArray();
				}

				return null;
			}

			public Object getParent(Object element) {
				if (element instanceof ElementPathNode) {
					ElementPathNode pn = (ElementPathNode) element;
					return pn.getParent();
				}
				return null;
			}

			public boolean hasChildren(Object element) {
				if (element instanceof ElementPathNode) {
					ElementPathNode pn = (ElementPathNode) element;
					return pn.hasChildren();
				}
				return false;
			}

			public void inputChanged(Viewer viewer, Object oldInput,
					Object newInput) {
			}
		});

		// setLabelProvider
		setLabelProvider(new ITableLabelProvider() {
			public void addListener(ILabelProviderListener listener) {
			}

			public void dispose() {
			}

			public Image getColumnImage(Object element, int columnIndex) {
				if (element instanceof ElementPathNode) {
					ElementPathNode pn = (ElementPathNode) element;
					if (pn.equals(pn.getInElementPath().getCurrPathNode()))
						return rightImg;
				}
				return null;
			}

			public String getColumnText(Object element, int columnIndex) {
				if (element instanceof ElementPathNode) {
					ElementPathNode pn = (ElementPathNode) element;
					return pn.getPElement().getName();
				}

				return null;
			}

			public boolean isLabelProperty(Object element, String property) {
				return false;
			}

			public void removeListener(ILabelProviderListener listener) {
			}
		});

		// wenn ein TreeNode klickt
		tree.addMouseListener(new MouseAdapter() {
			public void mouseDown(MouseEvent e) {

				TreeItem treeItem = tree.getItem(new Point(e.x, e.y));
				if (treeItem == null && e.button != 3) {
					tree.deselectAll();
					return;
				}

				IStructuredSelection selection = (IStructuredSelection) getSelection();

				final ElementPathNode pn = (ElementPathNode) selection
						.getFirstElement();

				if (pn == null)
					return;

				// Attribute Werte anzeigen
				// createAttrValTree(pn, attrValComp, attrValTreeMap);
				String selectElementName = pn.getPElement().getName();

				if (e.button == 3) {
					Menu positionMenu = new Menu(shell, SWT.POP_UP);

					// Vater Element hinzufuegen.
					{
						MenuItem addParent = new MenuItem(positionMenu,
								SWT.CASCADE);
						Menu parentMenu = new Menu(shell, SWT.DROP_DOWN);
						addParent.setMenu(parentMenu);
						addParent.setText(" + "
								+ GuiMessages.Stileditor_Gui_ParentNode);
						// Wenn die Knoten ein Parent hat,dann ungueltig
						if (pn.getParent() != null)
							addParent.setEnabled(false);
						else {

							List<Element> allList = getDocNodes("//"
									+ selectElementName, xmlScanner.getXml(),
									xmlScanner.getSimpleNamespaceContext());

							// @SuppressWarnings("unchecked")
							// List<Element> allList = simpleXmlOfInput
							// .selectNodes("//" + selectElementName);

							Set<String> parentSet = new HashSet<String>();
							String childrenPath = "/"
									+ pn.getInElementPath()
											.getSimplePathString(false);
							for (Element ce : allList) {
								if (getDocNodes(childrenPath, ce,
										xmlScanner.getSimpleNamespaceContext())
										.size() > 0 && ce.getParent() != null)
									parentSet.add(ce.getParent().getName());

								/*
								 * if (ce.selectNodes(childrenPath).size() > 0
								 * && ce.getParent() != null)
								 * parentSet.add(ce.getParent().getName());
								 */
							}

							if (parentSet.size() > 0) {
								Iterator<String> parentIt = parentSet
										.iterator();
								while (parentIt.hasNext()) {
									final MenuItem mi = new MenuItem(
											parentMenu, SWT.PUSH);
									mi.setText(parentIt.next());
									mi.addListener(SWT.Selection,
											new Listener() {
												public void handleEvent(
														Event event) {
													pn.getInElementPath()
															.addNode(
																	new ElementPathNode(
																			new PElement(
																					mi.getText())),
																	pn);

													updateControl();
												}
											});
								}

							} else
								addParent.setEnabled(false);
						}
					}

					// Kinder Element hinzufuegen.
					{
						MenuItem addChildren = new MenuItem(positionMenu,
								SWT.CASCADE);
						Menu childrenMenu = new Menu(shell, SWT.DROP_DOWN);
						addChildren.setMenu(childrenMenu);
						addChildren.setText(" + "
								+ GuiMessages.Stileditor_Gui_ChildNode);
						// Wenn die Knode Kinder hat,dann ungueltig
						if (pn.hasChildren())
							addChildren.setEnabled(false);
						else {
							List<Element> childrenList = getDocNodes("//"
									+ pn.getInElementPath()
											.getSimplePathString(true) + "/*",
									xmlScanner.getXml(),
									xmlScanner.getSimpleNamespaceContext());
							/*
							 * @SuppressWarnings("unchecked") List<Element>
							 * childrenList = simpleXmlOfInput .getXml()
							 * .selectNodes( "//" + pn.getInElementPath()
							 * .getSimplePathString( true) + "/*");
							 */
							Set<String> childrenSet = new HashSet<String>();

							for (Element ce : childrenList) {
								childrenSet.add(ce.getName());
							}

							if (childrenSet.size() > 0) {
								Iterator<String> childrenIt = childrenSet
										.iterator();
								while (childrenIt.hasNext()) {
									{
										final MenuItem mc = new MenuItem(
												childrenMenu, SWT.PUSH);
										mc.setText(childrenIt.next());
										mc.addListener(SWT.Selection,
												new Listener() {
													public void handleEvent(
															Event event) {
														pn.getInElementPath()
																.addNode(
																		pn,
																		new ElementPathNode(
																				new PElement(
																						mc.getText())));
														updateControl();
													}
												});
									}
								}
							} else
								addChildren.setEnabled(false);
						}
					}

					// TreeNode entfernen
					MenuItem delItem = new MenuItem(positionMenu, SWT.PUSH);
					delItem.setText(GuiMessages.General_Gui_Delete);
					if (pn.equals(pn.getInElementPath().getCurrPathNode()))
						delItem.setEnabled(false);

					delItem.addListener(SWT.Selection, new Listener() {
						public void handleEvent(Event e) {
							pn.getInElementPath().removeNode(pn);
							updateControl();
						}
					});

					positionMenu.setVisible(true);

				} else {
					updateControl();
					notifyObservers();
					// attrValTreeViewer.setInput(pn);
					// attrValTreeViewer.refresh();
					// attrValTreeViewer.expandAll();
					// setAttrValTvChecked(attrValTreeViewer, pn);

				}
			}

		});

	}

	@Override
	public void notifyObservers() {
		// TODO Auto-generated method stub
	}

	@Override
	public void registerObserver(IObserverControl observer) {
		// TODO Auto-generated method stub

	}

	@Override
	public void removeObserver(IObserverControl observer) {
		// TODO Auto-generated method stub

	}

	@Override
	public void setPrintProject(PrintProject pProject) {
		xmlScanner = pProject.getXMLScanner(false);
	}

	@Override
	public void updateControl() {
		refresh();
		expandAll();
	}

}
